package process

import (
	"context"
	"dmsv/agent"
	"dmsv/call"
	"dmsv/common"
	"dmsv/ivr"
	"dmsv/models"
	"dmsv/queue"
	"dmsv/session"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	weeklen = 7

	transfer_type_service = "service"
	transfer_type_queue   = "queue"
	transfer_type_ivr     = "ivr"

	play_service_id_call_in  = "in"
	play_service_id_call_out = "out"
	play_service_id_all      = "all"
	play_service_id_off      = "off"

	voice_wait_answer          = "/data/media/basic/waitanswer.wav"
	voice_off_work             = "/data/media/basic/offwork.wav"
	voice_say_goodbye          = "/data/media/basic/saygoodbye.wav"
	voice_leave_msg            = "/data/media/basic/leavemsg.wav"
	voice_wrong_key            = "/data/media/basic/wrongkey.wav"
	voice_satisfaction         = "/data/media/basic/satisfaction.wav"
	voice_satisfaction_goodbye = "/data/media/basic/satisfactiongoodbye.wav"
	voice_wait_delay_init      = 0

	voice_disable = "disable"
)

type displayInfo struct {
	display string
	count   int
}

type IvrTimeActive struct {
	ActiveFrom time.Time
	ActiveEnd  time.Time
}

type IvrInfo struct {
	ivrId      string
	name       string
	number     string
	ivrHandle  ivr.Handle
	activeTime []IvrTimeActive
	activeDay  [weeklen]bool
}

func (this IvrInfo) IsActive() bool {

	now := time.Now()
	dateOfWeek := int(now.Weekday())

	if this.activeDay[dateOfWeek] == false {
		logs.Debug("[%v] 休息时间: %v,今天周[%v]休息", this.ivrId, this.activeDay, dateOfWeek)
		return false
	}

	judge := now.AddDate(-now.Year(), -int(now.Month())+1, -now.Day()+1)
	for _, t := range this.activeTime {

		logs.Debug("[%v] 起始:%v ,结束:%v，当前:%v",
			this.ivrId, t.ActiveFrom.Format("2006-01-02 15:04:05"),
			t.ActiveEnd.Format("2006-01-02 15:04:05"),
			judge.Format("2006-01-02 15:04:05"),
		)

		if judge.After(t.ActiveFrom) && judge.Before(t.ActiveEnd) {
			return true
		}
	}

	return false
}

type TransferInfo struct {
	method string //转接类型:queue-技能组；service-坐席 ivr-ivr
	info   string //具体内容
}

type satisfactionConf struct {
	Active   bool
	AutoSend bool
	TipVoice string
	EndVoice string
}

type waitAudioConf struct {
	waitVoice     string
	endVoice      string
	stopSecond    int    //播放结束后停顿时长
	playTimes     int    //等待音播放次数
	bLeaveMsg     bool   //挂机前留言语音
	offwork       string //下班语音
	bOffworkLeave bool   //下班开启留言
	leaveVoice    string //下班留言语音
}

type Company struct {
	appId          string
	navigateAudio  string
	acd            string //技能组分发模式
	getKey         bool
	agLock         sync.RWMutex
	service        map[string]*agent.AgentInfo
	number         string
	display        []displayInfo
	guesCalltask   sync.Map
	waitTime       time.Duration
	callEventChan  chan *session.CallBackData //消息事件
	queEventChan   chan *queue.Event          //队列事件
	callInTransfer map[string]TransferInfo    //号码呼入转接配置，未配置为默认ivr
	resetTask      string
	playServiceId  string
	basic          AppBasicConfig
	satisfaction   satisfactionConf
	waitVoice      waitAudioConf
	ivrs           []*IvrInfo
}

var gEterpriceHandle map[string]*Company

//技能组分配模式
func (c *Company) Distribution() string {
	return c.acd
}

func (c *Company) SetOffWorkVoice(offwork, leaveVoice, leaveMsg string) {

	if len(offwork) > 0 {
		c.waitVoice.offwork = common.MediaFullPath(c.appId, offwork)
	}

	if len(leaveVoice) > 0 {
		c.waitVoice.leaveVoice = common.MediaFullPath(c.appId, leaveVoice)
	}

	if len(leaveMsg) > 0 {
		if leaveMsg == "open" {
			c.waitVoice.bOffworkLeave = true
		} else {
			c.waitVoice.bOffworkLeave = false
		}
	}
}

func (c *Company) SetWaitInfo(waitVoice, endVoice, leaveMsg string, playTimes, stopSecond int) {

	if stopSecond > 0 {
		c.waitVoice.stopSecond = stopSecond
	}

	if playTimes > 0 {
		c.waitVoice.playTimes = playTimes
	}
	if len(leaveMsg) > 0 {
		if leaveMsg == "true" {
			c.waitVoice.bLeaveMsg = true
		} else {
			c.waitVoice.bLeaveMsg = false
		}
	}

	if len(waitVoice) > 0 {
		c.waitVoice.waitVoice = waitVoice
	}

	if len(endVoice) > 0 {
		if endVoice == voice_disable {
			c.waitVoice.endVoice = ""
		} else {
			c.waitVoice.endVoice = endVoice
		}
	}

	logs.Debug("设置基础语音[%v],停顿时间:%v s,等待语音:%v ,播放次数:%v ,转留言开关:%v ,挂机结束语音:%v",
		c.appId, c.waitVoice.stopSecond, c.waitVoice.waitVoice, c.waitVoice.playTimes, c.waitVoice.bLeaveMsg, c.waitVoice.endVoice)
	models.StoreBasicVoice(c.appId, c.waitVoice.waitVoice, endVoice, c.waitVoice.playTimes,
		c.waitVoice.stopSecond, c.waitVoice.bLeaveMsg)
}

func (c *Company) NeedPlayServiceId(callType session.CallMethod) bool {

	result := false
	switch c.playServiceId {

	case play_service_id_call_in:
		//呼入打开
		if callType == session.CALL_TYPE_IN {
			result = true
		}

	case play_service_id_call_out:
		//呼出打开
		if callType != session.CALL_TYPE_IN {
			result = true
		}

	case play_service_id_all:
		//全部打开
		result = true
	default:
		result = false
	}
	return result
}

func (c *Company) SetPlayServiceId(arg string) {

	switch arg {
	case "all_close":
		c.playServiceId = play_service_id_off
	case "all_start":
		c.playServiceId = play_service_id_all
	case "called_start":
		//呼入开启
		c.playServiceId = play_service_id_call_in
	case "caller_start":
		//呼出开启
		c.playServiceId = play_service_id_call_out
	default:
		c.playServiceId = play_service_id_off
	}

	logs.Debug("[%v]设置播放坐席工号:%v", c.appId, c.playServiceId)
}

func (c *Company) TestDebugPrintIvr() {

	for _, ivr := range c.ivrs {

		logs.Info("ivr id:[%4v],ivr 名称:%v.", ivr.ivrId, ivr.name)

	}
}

func (c *Company) SetTransfer(number string, transfer, args string) {

	newInfo := TransferInfo{
		method: transfer,
		info:   args,
	}

	c.callInTransfer[number] = newInfo
	if transfer == transfer_type_service {

		logs.Debug("appId:%v number:%v 设置 转坐席:%v", c.GetAppId(), number, args)
	} else if transfer == transfer_type_queue {

		logs.Debug("appId:%v number:%v 设置 转队列:%v", c.GetAppId(), number, args)
	} else if transfer == transfer_type_ivr {

		logs.Debug("appId:%v number:%v 设置 转Ivr:%v", c.GetAppId(), number, args)

	}
	err := session.AddCallInNumber(number, c.callEventChan)
	if err != nil {
		logs.Info("[%v] 已添加过", number)
	}
}

func (c *Company) SatisfactionConfig(active, autoSend, tipVoice, endVoice string) {

	if len(active) > 0 {
		if strings.HasPrefix(active, "true") {
			c.satisfaction.Active = true
		} else if strings.HasPrefix(active, "false") {
			c.satisfaction.Active = false
		}
	}

	if len(autoSend) > 0 {
		if strings.HasPrefix(autoSend, "true") {
			c.satisfaction.AutoSend = true
		} else {
			c.satisfaction.AutoSend = false
		}
	}

	if len(tipVoice) > 0 {
		c.satisfaction.TipVoice = tipVoice
	}

	if len(endVoice) > 0 {
		c.satisfaction.EndVoice = endVoice
	}

}

func (c *Company) satisfactionActive() bool {
	return c.satisfaction.Active
}

func (c *Company) satisfactionAuto() bool {
	return c.satisfaction.AutoSend
}

func (c *Company) satisfactionPlayFile() string {
	return c.satisfaction.TipVoice
}

func (c *Company) startIvrSession(ss *session.SessionInfo, ivrId string) bool {

	if len(c.ivrs) > 0 {

		//优先根据中继号匹配
		for _, ivr := range c.ivrs {

			if ivrId == ivr.ivrId {
				logs.Debug("[%v]找到绑定Ivr流程,ivr MangerId %v - 名称:%v  . ",
					ss.GetSessionId(), ivr.ivrId, ivr.name)

				//时间判断
				if ivr.IsActive() {
					ss.StartIvr(ivr.ivrHandle)
				} else {
					logs.Debug("[%v] 非有效时间内 ivr 播放下班语音[%v]，留言结束语音:%v",
						ss.GetSessionId(), c.waitVoice.offwork, c.waitVoice.leaveVoice)

					if false == common.FileIsExist(c.waitVoice.offwork) {
						ss.HangUp(common.ErrNoFile)
						return false
					}

					//开启留言
					if true == c.waitVoice.bOffworkLeave {
						//放音后留言
						ss.LeaveMessage(c.waitVoice.offwork, c.waitVoice.leaveVoice)
					} else {
						//不留言的情况下 放音完成后挂机
						ss.HangUpAfterPlay(c.waitVoice.offwork)
					}
				}
				return true
			}
		}
		logs.Error("[%v] 未匹配到 IvrId %v,挂机", ss.GetSessionId(), ivrId)
		ss.HangUp(common.ErrIvrInit)
	}

	return false
}

func (c *Company) GetAppId() string {
	return c.appId
}

func (c *Company) newCallIn(msg *session.CallBackData) {

	//呼入入队处理
	nc := msg.Data.(*call.CallInfo)
	if nc == nil {
		logs.Error("call info is nil")
		return
	}

	//呼入主叫为黑名单；直接挂机处理
	if true == models.JudgeBlackList(c.appId, nc.Caller) {
		logs.Debug("%v caller%v is in the black list.hang up", nc.CallId(), nc.Caller)
		nc.ErrHangUp(common.ErrNumberBlack)
		return
	}

	//创建session
	callId := createUUid()
	session.CreateSessionCallIn(c.appId, callId, nc, c.callEventChan)

}

func (c *Company) callInTransferTo(callIn *session.SessionInfo) bool {

	if transfer, ok := c.callInTransfer[callIn.Callee()]; ok {

		logs.Debug("[%v] 呼入类型查找, number:%v ,类型:%v ,内容:%v",
			callIn.GetSessionId(), callIn.Callee(), transfer.method, transfer.info)
		//转技能组
		if transfer.method == transfer_type_queue {

			//发送接听通知
			callIn.AnswerRpt("", transfer_type_queue, false)

			queId, err := strconv.Atoi(transfer.info)
			res := true

			if err != nil {
				logs.Error("get transfer queId failed:%v", err, transfer)
				res = queue.AddNewCallToQueue(c.appId, "default", callIn)
			} else {
				lastService := ""
				if c.basic.BindModel {
					serviceId, err := models.GetLatestServiceId(c.appId, callIn.Caller())
					if err != nil {
						logs.Error("[%v]获取上次联络坐席失败:%v", callIn.GetSessionId(), callIn.Caller())
					}
					lastService = serviceId
				}

				res = queue.AddNewCallToQueueById(c.appId, lastService, queId, callIn)
			}
			logs.Debug("直接转技能组:%v :结果:%v ", queId, res)

			return true
		} else if transfer.method == transfer_type_service {

			logs.Debug("[%v] 呼入转坐席 :%v", callIn.GetSessionId(), transfer.info)

			callIn.SetService(transfer.info)
			agent, exist := c.GetService(transfer.info)
			if exist {
				logs.Debug("[%v]serviceId:%v 坐席状态 :%v,坐席电话状态:%v",
					callIn.GetSessionId(), agent.ServiceId(), agent.Status(), agent.PhoneStatus())

				media := common.MediaFullPath(c.appId, c.waitVoice.waitVoice)
				secondMedia := common.MediaFullPath(c.appId, c.waitVoice.endVoice)
				args := session.WaitInfo{
					PlayTimes: c.waitVoice.playTimes,
					Delay:     c.waitVoice.stopSecond,
					Media:     media,
					SecMedia:  secondMedia,
					BLeaveMsg: c.waitVoice.bLeaveMsg,
				}

				if agent.IsFree() {
					callIn.CallService(agent, args)
				} else {
					callIn.PlayWait(args)
				}
				callIn.AnswerRpt("", transfer_type_service, false)
			} else {
				logs.Error("[%v] 未找到坐席 %v ...", callIn.GetSessionId(), transfer.info)
				callIn.HangUp(common.ErrServiceNotSign)
			}

			return true
		} else {
			//发送接听通知
			callIn.AnswerRpt("", transfer_type_ivr, false)
			// ivr 流程
			return c.startIvrSession(callIn, transfer.info)
		}
	}
	logs.Error("[%v] 呼入号码未配置类型, number:%v ", callIn.GetSessionId(), callIn.Callee)
	return false
}

func (c *Company) callAnswer(msg *session.CallBackData) {

	//坐席接听后处理
	if msg.Dir == session.LEG_DIR_SERVICE {

		//坐席示忙需要重新计次
		agent, ok := c.GetService(msg.Ssion.GetServiceId())
		if ok {
			agent.MisCallReset()
			logs.Debug("[%v]坐席接听, 重新计算misCall.", msg.Ssion.GetSessionId())
		}

		//播放工号
		c.PlayServiceId(msg.Ssion)
	} else if msg.Dir == session.LEG_DIR_USER {
		//用户侧 设置桥接挂机参数
		msg.Ssion.HoldTheCall()

		//开启录音
		fileName := createRecordName(msg.CallId, msg.Caller, msg.Callee)
		msg.Ssion.StartRecord(fileName)

		logs.Debug("[%v] start record,fileName:%v", msg.CallId, fileName)

		//根据企业号码的呼入配置进入不同的流程 呼叫中心处理流程
		c.callInTransferTo(msg.Ssion)
	}
}

func (c *Company) callEventProcess(ev *session.CallBackData) {

	if ev == nil {
		return
	}
	var rs common.StatusCode
	bRingSend := false
	switch ev.Event {
	case session.CALL_EVENT_FAIL:

		//呼叫坐席失败
		logs.Debug("[%v]呼叫坐席失败:%v", ev.CallId, ev.Data)
		ev.Ssion.HangUp(ev.Data)

	case session.CALL_EVENT_START:
		//新的呼叫事件
		c.newCallIn(ev)
	case session.CALL_EVENT_RING:
		logs.Debug("[%v] 振铃通知,dir :%v ", ev.CallId, ev.Dir)
		//发送坐席振铃通知
		if ev.Dir == session.LEG_DIR_SERVICE {
			//logs.Debug("[%v] 发送振铃通知,dir :%v ，serviceId:%v", ev.CallId, ev.Dir, ev.Ssion.GetServiceId())
			if false == bRingSend {
				ev.Ssion.RingRpt(ev.Ssion.GetServiceId(), false)
				bRingSend = true
			}
		} else if ev.Dir == session.LEG_DIR_USER {
			//呼入侧，不需要发送呼叫用户的通知
			//ev.Ssion.RingRpt(ev.Ssion.GetServiceId())
		} else {
			if len(ev.Dir) != 0 {
				logs.Debug("[%v] 发送振铃通知,dir :%v ，serviceId:%v", ev.CallId, ev.Dir, ev.Ssion.GetServiceId())
				ev.Ssion.RingRpt("", false)
			}
		}

	case session.CALL_EVENT_ANSWER:

		c.callAnswer(ev)
		//发送坐席接听通知
		if ev.Dir == session.LEG_DIR_SERVICE {
			ev.Ssion.AnswerRpt(ev.Ssion.GetServiceId(), "", false)
		} else if ev.Dir == session.LEG_DIR_THIRD {
			ev.Ssion.AnswerRpt("", "", false)
		}
	case session.CALL_EVENT_TO_NUMBER:
		logs.Debug("[%v]转外线:%v ....", ev.CallId, ev.Data)

	case session.CALL_EVENT_TO_SERVICE:
		//ivr过程中转坐席
		media := common.MediaFullPath(c.appId, c.waitVoice.waitVoice)
		secondMedia := common.MediaFullPath(c.appId, c.waitVoice.endVoice)

		args := session.WaitInfo{
			Media:     media,
			SecMedia:  secondMedia,
			BLeaveMsg: c.waitVoice.bLeaveMsg,
			Delay:     c.waitVoice.stopSecond,
			PlayTimes: c.waitVoice.playTimes,
		}

		serviceId, ok := ev.Data.(string)
		if !ok {
			logs.Error("[%v] 数据不正确 :%v ,", ev.CallId, ev.Data)
			ev.Ssion.HangUp(common.ErrSystem)
			return
		}

		//设置坐席Id，即使未真正转坐席，也需要设置坐席Id
		ev.Ssion.SetService(serviceId)
		service, err := agent.GetAgentInfoByService(c.appId, serviceId)
		if err != nil {
			logs.Error("[%v] 未找到app[%v]对应的坐席:%v", ev.CallId, c.appId, serviceId)
			ev.Ssion.HangUp(common.ErrServiceNotSign)
			return
		}

		if service.IsFree() {
			ev.Ssion.CallService(service, args)
		} else {
			ev.Ssion.PlayWait(args)
		}

	case session.CALL_EVENT_DTMF:

		dtmf := ev.Data.(string)
		logs.Debug("[%v] 用户按键: %v ", ev.CallId, dtmf)
		success := true

		if dtmf == "" {
			//超时直接进入默认队列
			success = queue.AddNewCallToQueue(c.appId, "default", ev.Ssion)
		} else {
			lastService := ""
			if c.basic.BindModel {
				serviceId, err := models.GetLatestServiceId(c.appId, ev.Ssion.Caller())
				if err != nil {
					logs.Error("[%v]获取上次联络坐席失败:%v", ev.CallId, ev.Ssion.Caller())
				}
				lastService = serviceId
			}

			if false == queue.AddNewCallToQueueByKey(c.appId, dtmf, lastService, ev.Ssion) {
				logs.Error("[%v] enqueue failed,change default que", ev.CallId)
				success = queue.AddNewCallToQueue(c.appId, "default", ev.Ssion)
			}
		}
		if !success {
			logs.Error("[%v] enqueue failed,hangup the call", ev.CallId)
			ev.Ssion.HangUp(common.ErrCallerEnQueue)
		}

	case session.CALL_EVENT_ENQUE:
		//入队
		queId, ok := ev.Data.(int64)
		if ok {
			lastService := ""
			if c.basic.BindModel {
				serviceId, err := models.GetLatestServiceId(c.appId, ev.Ssion.Caller())
				if err != nil {
					logs.Error("[%v]获取上次联络坐席失败:%v", ev.CallId, ev.Ssion.Caller())
				}
				lastService = serviceId
			}
			logs.Debug("[%v] 入队消息:%v", ev.CallId, queId)
			res := queue.AddNewCallToQueueById(c.appId, lastService, int(queId), ev.Ssion)
			if false == res {
				logs.Error("[%v] enqueue failed,change default que", ev.CallId)
			}

		} else {
			logs.Debug("[%v] 节能组Id错误: %v ", ev.CallId, queId)
		}

	//放音结束(根据当前菜单状态,继续放音)
	case session.CALL_EVENT_PLAY_OVER:

		//ev.Call.RePlay()
	case session.CALL_EVENT_SATISFACTION:
		media := common.MediaFullPath(c.GetAppId(), c.satisfaction.EndVoice)
		ev.Ssion.HangUpAfterPlay(media)

	case session.CALL_EVENT_DESTROY:
		//用户挂机 结束会话
		hangInfo := ev.Data.(*session.HangInfo)
		logs.Debug("[%v]user call:%v is finished,通话时长:%v,挂机原因:%v",
			ev.CallId, ev.Ssion.GetServiceId(), hangInfo.Duration, hangInfo.Reason)
		if hangInfo.Reason == nil {

			//默认坐席未接听，主叫挂断
			rs = common.ErrCallerHangup
			if ev.Ssion.IsServiceAnswer() {
				//坐席接听，主叫挂断
				rs = common.SuccCalleeHangup
			}
		}

		ev.Ssion.SendBill(gCallBack, rs)

	case session.CALL_EVENT_HANGUP:

		hangInfo := ev.Data.(*session.HangInfo)
		if len(hangInfo.ServiceId) > 0 {
			//坐席挂机 设置电话空闲
			if s, ok := c.GetService(hangInfo.ServiceId); ok {
				s.SetPhoneFree(hangInfo.Duration, true)
			} else {
				logs.Error("[%v] serviceId %v is 未签入.", ev.CallId, hangInfo.ServiceId)
			}
		}

		//推送坐席挂机通知
		ev.Ssion.ServiceHangUpRpt(hangInfo.ServiceId, "")

		logs.Debug("[%v]service: [%v] is finished,挂机原因:%v,sipCode:%v,坐席通话时长:%v，示忙开关:%v",
			ev.CallId, ev.Ssion.GetServiceId(), hangInfo.Reason, hangInfo.SipCode, hangInfo.Duration, c.basic.ErrPass)

		//坐席未接听
		if hangInfo.Duration == 0 {
			if hangInfo.Reason == common.HANG_UP_USER {
				logs.Debug("[%v] 用户主动挂机,不计入坐席未接次数", ev.CallId)
				break
			}

			//处于技能组的坐席通话，才需要计算次数
			if c.basic.ErrPass && hangInfo.QueId > 0 {
				logs.Debug("[%v]自动示忙开关打开.坐席计数", ev.CallId)
				agent, ok := c.GetService(hangInfo.ServiceId)
				if ok {
					//自动示忙
					if agent.MisCallPlus() >= c.basic.ErrNo {
						logs.Info("appid[%v] 坐席未接来电已达到自动示忙次数[%v/%v]，坐席示忙",
							c.appId, agent.MissCall(), c.basic.ErrNo)
						agent.SetBusy()
						agent.WsSendSetBusy()
					}
				}
			}
		} else {
			//坐席已接听
			if c.satisfactionActive() && c.satisfactionAuto() {
				//自动启动满意度调查
				media := common.MediaFullPath(c.GetAppId(), c.satisfactionPlayFile())
				ev.Ssion.Satisfaction(media)
			} else {

				ev.Ssion.Destroy(common.SuccServiceHang)
			}

			if c.basic.Arrange {
				agent, ok := c.GetService(hangInfo.ServiceId)
				if ok {
					logs.Info("appid[%v] 设置坐席[%v]整理时间 ",
						c.appId, agent.ServiceId())
					agent.SetNextAnswer(c.basic.ArrangeTime)
				}
			}
		}

	//其他事件处理
	default:
		logs.Debug("[%v]收到事件[%V].", ev.CallId, ev.Event)
	}
}

func (c *Company) PlayServiceId(ss *session.SessionInfo) error {

	if false == c.NeedPlayServiceId(ss.CallType()) {
		logs.Debug("[%v]坐席接听, 不需要播放工号.", ss.GetSessionId())

		ss.BridgeUser()
		return nil
	}

	logs.Debug("[%v]坐席接听, 播放坐席工号：%v", ss.GetSessionId(), ss.GetServiceId())

	//需要播放工号 放音后，在ivr中呼叫坐席
	mediaFile := fmt.Sprintf("file_string://%s%s", gMediaDir, "gonghao.wav")
	/*for _, v := range ss.GetServiceId() {
		mediaFile += fmt.Sprintf("!%s%c.wav", gMediaDir, v)
	}
	*/
	mediaFile += fmt.Sprintf("!%sservice/%s.wav", gMediaDir, ss.GetServiceId())
	//增加"为您服务"语音
	mediaFile += fmt.Sprintf("!%s%s", gMediaDir, "serveu.wav")
	ss.PlayAndBridge("", mediaFile)
	return nil

}

func (c *Company) queueEventProcess(event *queue.Event) {
	switch event.Name {
	case queue.QUE_EVENT_TIME_OUT:
		//入队超时
		logs.Error("%v call enque time out.hang up", event.Ssion.GetSessionId())

	case queue.QUE_EVENT_SUCCESS:

		//入队成功,播放等待音
		args := session.WaitInfo{
			Media:     common.MediaFullPath(c.appId, c.waitVoice.waitVoice),
			SecMedia:  common.MediaFullPath(c.appId, c.waitVoice.endVoice),
			PlayTimes: c.waitVoice.playTimes,
			Delay:     c.waitVoice.stopSecond,
			BLeaveMsg: c.waitVoice.bLeaveMsg,
		}
		event.Ssion.PlayWait(args)

		//发送入队通知
		event.Ssion.EnQueueRpt(event.QueId)

	case queue.QUE_EVENT_CALLEE_UNREACH:
		//转接失败
		logs.Error("%v call transfer to service failed.hang up", event.Ssion.GetSessionId())

	case queue.QUE_EVENT_FIND_SERVICE:

		logs.Info("%v 呼叫坐席:%v-%v", event.Ssion.GetSessionId(), event.Service.ServiceId(), event.Service.Number())

		// 呼叫坐席
		err := event.Ssion.CallServiceWithOutPlay(event.Service)
		if err != nil {
			event.Service.SetPhoneFree(0, true)
			logs.Error("%v call transfer to service failed.hang up", event.Ssion.GetSessionId())
		}
	case queue.QUE_EVENT_CALLER_HANGUP:

		logs.Debug("%v call is hang up", event.Ssion.GetSessionId())
		event.Ssion.HangUp(common.ErrCallerHangup)

	default:
		logs.Error("%v call event:%v", event.Ssion.GetSessionId(), event.Name)
	}
}

func (c *Company) callInProcess() {

	for {
		select {

		//呼叫事件
		case ev, ok := <-c.callEventChan:
			if !ok {
				logs.Warn("company:%v call in task quit", c.appId)
				return
			}
			go c.callEventProcess(ev)

			//排队事件
		case event := <-c.queEventChan:

			go c.queueEventProcess(event)
		}
	}
}

func (c *Company) GetDisplay() string {

	return c.number
}

func (c *Company) GetService(serviceId string) (*agent.AgentInfo, bool) {

	c.agLock.RLock()
	defer c.agLock.RUnlock()

	s, ok := c.service[serviceId]
	return s, ok
}

func (c *Company) serviceReset(ctx context.Context) error {

	logs.Debug("%v start reset service", c.resetTask)
	for _, s := range c.service {
		s.Reset()
	}

	return nil
}

func (c *Company) AddDisplay(number string) error {

	logs.Debug("企业:%v 添加外显号:%v", c.GetAppId(), number)
	for _, n := range c.display {
		if n.display == number {
			return nil
		}
	}

	newDisplay := displayInfo{
		display: number,
	}

	c.display = append(c.display, newDisplay)

	return nil
}

func (c *Company) DelDisplay(number string) {

	for i, n := range c.display {
		if n.display == number {
			c.display = append(c.display[:i], c.display[i+1:]...)
			break
		}
	}

	return
}

func (c *Company) ListenNumber(number string) error {
	logs.Debug("企业:%v 添加呼入 number:%v", c.GetAppId(), number)
	return session.AddCallInNumber(number, c.callEventChan)
}

func (c *Company) DelListenNumber(number string) {
	session.DelListenNumber(number)
}

func (c *Company) AddNewIvrManage(ivrId, name, number string, handle ivr.Handle, activeTime []IvrTimeActive, day [weeklen]bool) {

	info := &IvrInfo{
		ivrId:      ivrId,
		name:       name,
		number:     number,
		ivrHandle:  handle,
		activeTime: activeTime,
		activeDay:  day,
	}

	logs.Debug("加载ivr流程 [%v] %v 绑定中继号:%v,生效时段:%v ,生效日:%v",
		ivrId, name, number, activeTime, day)
	c.ivrs = append(c.ivrs, info)
}

func IvrManageAdd(ivrId, appId, name, number string, activeTime []IvrTimeActive, day [weeklen]bool) error {
	handle, ok := gEterpriceHandle[appId]
	if ok {

		info := &IvrInfo{
			ivrId:      ivrId,
			name:       name,
			number:     number,
			activeTime: activeTime,
			activeDay:  day,
		}

		logs.Debug("appId:%v ,ivr[%v]生效星期:%v", appId, ivrId, day)

		handle.ivrs = append(handle.ivrs, info)
		return nil
	}

	return errors.New("NoCompany")
}

func IvrManageUpdate(ivrId, appId, name, number string, activeTime []IvrTimeActive, day [weeklen]bool) error {

	handle, ok := gEterpriceHandle[appId]
	if ok {
		for _, ivr := range handle.ivrs {
			if ivr.ivrId == ivrId {
				if name != "" {
					ivr.name = name
				}

				if number != "" {
					ivr.number = number
				}
				ivr.activeTime = activeTime
				ivr.activeDay = day

			}
		}

		return nil
	}

	return errors.New("NoCompany")
}

func IvrManageDel(ivrId, appId string) error {
	handle, ok := gEterpriceHandle[appId]
	if ok {
		for i, ivr := range handle.ivrs {
			if ivr.ivrId == ivrId {
				handle.ivrs = append(handle.ivrs[:i], handle.ivrs[i+1:]...)
				break
			}
		}

		return nil
	}

	return errors.New("NoCompany")
}

func IvrManagePublish(ivrId, appId string) error {

	handle, ok := gEterpriceHandle[appId]
	if ok {
		logs.Debug("appid:%v 包含ivr流程:%2v 个,更新ivrId：%v ", appId, len(handle.ivrs), ivrId)
		for _, ivrm := range handle.ivrs {
			if ivrm.ivrId == ivrId {

				manageId, err := strconv.ParseInt(ivrId, 10, 64)
				if err != nil {
					logs.Error("ivr id convert fail:%v from :%v", err, ivrId)
					return errors.New("ivrIdErr")
				}

				go func() {

					time.Sleep(5 * time.Second)

					ivrHandle := ivr.InitHandle(appId, manageId)
					if ivrHandle == nil {
						logs.Error("ivr 初始化失败，节点有错误.")
					}

					ivrm.ivrHandle = *ivrHandle
				}()
				break
			}
		}

		return nil
	}

	return errors.New("NoCompany")
}

func SetCompanyWaitVoice(appId, waitVoice, endVoice, leavemsg string, playTimes, stopSecond int) error {

	handle, ok := gEterpriceHandle[appId]
	if ok {
		handle.SetWaitInfo(waitVoice, endVoice, leavemsg, playTimes, stopSecond)

		return nil
	} else {
		return errors.New("NoCompany")
	}
}

func SetCompanyOffWorkVoice(appId, offworkVoice, leaveVoice, leaveMsg string) error {

	handle, ok := gEterpriceHandle[appId]
	if ok {

		handle.SetOffWorkVoice(offworkVoice, leaveVoice, leaveMsg)
		models.StoreOffWork(appId, offworkVoice, leaveVoice, leaveMsg)
		return nil
	} else {
		return errors.New("NoCompany")
	}
}

func SetPlayServiceId(appId, args string) error {
	handle, ok := gEterpriceHandle[appId]
	if ok {
		handle.SetPlayServiceId(args)
		models.StorePlayServiceId(appId, args)
		return nil
	} else {
		return errors.New("NoCompany")
	}
}

const (
	BASIC_TYPE_ARRANGE     = "arrange"     //整理开关
	BASIC_TYPE_ARRANGE_T   = "arrangeTime" //整理时间
	BASIC_TYPE_BIND_MODEL  = "bindModel"   //是否熟客优先 true:是 ; false: 否
	BASIC_TYPE_AUTO_ANSWER = "autoAnswer"  //接入来电模式 true:手动接听;false:自动接听
	BASIC_TYPE_MIS_CALL    = "errPass"     //呼叫开启示忙  true: 开启;false:不开启
	BASIC_TYPE_MIS_NUMBER  = "errNumber"   //未接次数
)

func SetCompanyBasic(appId, confType string, value interface{}) error {

	handle, ok := gEterpriceHandle[appId]
	if ok {

		switch confType {
		//整理开关
		case BASIC_TYPE_ARRANGE:
			result, ok := value.(bool)
			if ok {
				handle.basic.Arrange = result
			}
		case BASIC_TYPE_ARRANGE_T:
			num, _ := strconv.Atoi(value.(string))
			handle.basic.ArrangeTime = num
		case BASIC_TYPE_BIND_MODEL:
			handle.basic.BindModel = value.(bool)
		case BASIC_TYPE_AUTO_ANSWER:
			handle.basic.AutoAnswer = value.(bool)
			//自动示忙时间
		case BASIC_TYPE_MIS_CALL:
			result, ok := value.(bool)
			if ok {
				logs.Debug("[%v] 原配置:%v,新配置:%v,判断结果:%v.", handle.appId,
					handle.basic.ErrPass, result, handle.basic.ErrPass == false && result == true)
				//关闭再打开该功能,需要重置计数
				if handle.basic.ErrPass == false && result == true {
					handle.agLock.RLock()
					for _, service := range handle.service {
						service.MisCallReset()
					}
					handle.agLock.RUnlock()
				}
				handle.basic.ErrPass = result
			}

		case BASIC_TYPE_MIS_NUMBER:
			num, _ := strconv.Atoi(value.(string))
			handle.basic.ErrNo = num
			/*if num < handle.basic.ErrNo {
				for _, service := range handle.service {
					service.MisCallReset()
				}
			}*/
		default:

		}
		data, err := json.Marshal(handle.basic)
		if err != nil {
			logs.Error("[%v] 基础配置存储前,转json失败:%v", appId, err)
			return nil
		}

		models.UpdateCompanyBasicData(appId, string(data))
		return nil
	} else {
		return errors.New("NoCompany")
	}
}

func (c *Company) LoadCompanyBasic(data string) {

	err := json.Unmarshal([]byte(data), &c.basic)
	if err != nil {
		logs.Error("[%v] 加载基础数据失败:%v", c.appId, err)
	} else {
		logs.Info("[%v] 加载基础数据成功:%v", c.appId, c.basic)

	}

}
